package common

import (
	"container/list"
)

// Keyer 接口，定义获取键的方法。
type Keyer interface {
	GetKey() interface{}
}

// MapList 是一个支持快速查找和有序遍历的容器。
type MapList struct {
	dataMap  map[interface{}]*list.Element
	dataList *list.List
}

// NewMapList 创建一个新的 MapList。
func NewMapList() *MapList {
	return &MapList{
		dataMap:  make(map[interface{}]*list.Element),
		dataList: list.New(),
	}
}

// Exists 检查指定数据是否存在。
func (mapList *MapList) Exists(data Keyer) bool {
	_, exists := mapList.dataMap[data.GetKey()]
	return exists
}

// Get 根据键获取数据。
func (mapList *MapList) Get(key interface{}) interface{} {
	v, ok := mapList.dataMap[key]
	if !ok {
		return nil
	}
	return v.Value
}

// Push 添加数据到 MapList。
// 如果数据已存在，则返回 false。
func (mapList *MapList) Push(data Keyer) bool {
	if mapList.Exists(data) {
		return false
	}
	elem := mapList.dataList.PushBack(data)
	mapList.dataMap[data.GetKey()] = elem
	return true
}

// Remove 移除指定数据。
func (mapList *MapList) Remove(data Keyer) {
	if !mapList.Exists(data) {
		return
	}
	mapList.dataList.Remove(mapList.dataMap[data.GetKey()])
	delete(mapList.dataMap, data.GetKey())
}

// Clear 清空 MapList。
func (mapList *MapList) Clear() {
	mapList.dataMap = make(map[interface{}]*list.Element)
	mapList.dataList = list.New()
}

// Size 返回 MapList 的大小。
func (mapList *MapList) Size() int {
	return mapList.dataList.Len()
}

// Walk 遍历 MapList，并对每个数据执行回调函数。
// 如果回调函数返回 false，则停止遍历。
func (mapList *MapList) Walk(cb func(data Keyer) bool) {
	var n *list.Element
	for elem := mapList.dataList.Front(); elem != nil; elem = n {
		n = elem.Next()
		if !cb(elem.Value.(Keyer)) {
			break
		}
	}
}

// WalkAndRemove 遍历 MapList，并移除满足条件的数据。
func (mapList *MapList) WalkAndRemove(cb func(data Keyer) bool) {
	var n *list.Element
	for elem := mapList.dataList.Front(); elem != nil; elem = n {
		n = elem.Next()
		keyer := elem.Value.(Keyer)
		if cb(keyer) {
			mapList.dataList.Remove(elem)
			delete(mapList.dataMap, keyer.GetKey())
		} else {
			break
		}
	}
}
